package org.fanjr.simplify.rest.storage;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.fanjr.simplify.rest.utils.SimplifyClassUtil;

/**
 * 
 * @author fanjr@vip.qq.com
 * @since 20190222 10:29:28
 */
public abstract class SimplifyStorage<K, V> {

	private final V NULLVALUE;

	private final Map<K, V> STORAGE = new ConcurrentHashMap<K, V>();

	protected SimplifyStorage() {
		NULLVALUE = newNullInstance();
	}

	protected V buildAndGet(K k, Object... args) {
		V v = STORAGE.get(k);
		if (null == v) {
			synchronized (k) {
				v = STORAGE.get(k);
				if (null == v) {
					v = buildFunction(k, args);
					if (null == v) {
						STORAGE.put(k, NULLVALUE);
						return null;
					} else {
						STORAGE.put(k, v);
					}
				}
			}
		}
		if (NULLVALUE == v) {
			return null;
		}
		return v;
	}

	protected V get(K k) {
		V v = STORAGE.get(k);
		if (NULLVALUE == v) {
			return null;
		}
		return v;
	}

	protected abstract V buildFunction(K k, Object[] args);

	@SuppressWarnings("unchecked")
	private V newNullInstance() {
		Type superClassType = this.getClass().getGenericSuperclass();
		Type valueType = ((ParameterizedType) superClassType).getActualTypeArguments()[1];
		if (valueType instanceof Class) {
			return SimplifyClassUtil.newSimpleInstance((Class<V>) valueType);
		} else {
			return SimplifyClassUtil.newSimpleInstance((Class<V>) ((ParameterizedType) valueType).getRawType());
		}
	}
}
